return gtk_css_value_new_from_array (array);
}
+GtkCssValue *
+gtk_css_calc_value_parse_value (GtkCssParser *parser,
+ GtkCssNumberParseFlags flags)
+{
+ if (_gtk_css_parser_has_prefix (parser, "calc"))
+ {
+ _gtk_css_parser_error (parser, "Nested calc() expressions are not allowed.");
+ return NULL;
+ }
+
+ return _gtk_css_number_value_parse (parser, flags);
+}
+
+static gboolean
+is_number (GtkCssValue *value)
+{
+ return gtk_css_number_value_get_dimension (value) == GTK_CSS_DIMENSION_NUMBER
+ && !gtk_css_number_value_has_percent (value);
+}
+
+GtkCssValue *
+gtk_css_calc_value_parse_product (GtkCssParser *parser,
+ GtkCssNumberParseFlags flags)
+{
+ GtkCssValue *result, *value, *temp;
+ GtkCssNumberParseFlags actual_flags;
+
+ actual_flags = flags | GTK_CSS_PARSE_NUMBER;
+
+ result = gtk_css_calc_value_parse_value (parser, actual_flags);
+ if (result == NULL)
+ return NULL;
+
+ while (_gtk_css_parser_begins_with (parser, '*') || _gtk_css_parser_begins_with (parser, '/'))
+ {
+ if (actual_flags != GTK_CSS_PARSE_NUMBER && !is_number (result))
+ actual_flags = GTK_CSS_PARSE_NUMBER;
+
+ if (_gtk_css_parser_try (parser, "*", TRUE))
+ {
+ value = gtk_css_calc_value_parse_product (parser, actual_flags);
+ if (value == NULL)
+ goto fail;
+ if (is_number (value))
+ temp = gtk_css_number_value_multiply (result, _gtk_css_number_value_get (value, 100));
+ else
+ temp = gtk_css_number_value_multiply (value, _gtk_css_number_value_get (result, 100));
+ _gtk_css_value_unref (value);
+ _gtk_css_value_unref (result);
+ result = temp;
+ }
+ else if (_gtk_css_parser_try (parser, "/", TRUE))
+ {
+ value = gtk_css_calc_value_parse_product (parser, GTK_CSS_PARSE_NUMBER);
+ if (value == NULL)
+ goto fail;
+ temp = gtk_css_number_value_multiply (result, 1.0 / _gtk_css_number_value_get (value, 100));
+ _gtk_css_value_unref (value);
+ _gtk_css_value_unref (result);
+ result = temp;
+ }
+ else
+ {
+ g_assert_not_reached ();
+ goto fail;
+ }
+ }
+
+ if (is_number (result) && !(flags & GTK_CSS_PARSE_NUMBER))
+ {
+ _gtk_css_parser_error (parser, "calc() product term has no units");
+ goto fail;
+ }
+
+ return result;
+
+fail:
+ _gtk_css_value_unref (result);
+ return NULL;
+}
+
GtkCssValue *
gtk_css_calc_value_parse_sum (GtkCssParser *parser,
GtkCssNumberParseFlags flags)
{
GtkCssValue *result;
- result = _gtk_css_number_value_parse (parser, flags);
+ result = gtk_css_calc_value_parse_product (parser, flags);
if (result == NULL)
return NULL;
if (_gtk_css_parser_try (parser, "+", TRUE))
{
- next = _gtk_css_number_value_parse (parser, flags);
+ next = gtk_css_calc_value_parse_product (parser, flags);
+ if (next == NULL)
+ goto fail;
}
else if (_gtk_css_parser_try (parser, "-", TRUE))
{
- temp = _gtk_css_number_value_parse (parser, flags);
+ temp = gtk_css_calc_value_parse_product (parser, flags);
+ if (temp == NULL)
+ goto fail;
next = gtk_css_number_value_multiply (temp, -1);
_gtk_css_value_unref (temp);
}
else
{
g_assert_not_reached ();
+ goto fail;
}
temp = gtk_css_number_value_add (result, next);
}
return result;
+
+fail:
+ _gtk_css_value_unref (result);
+ return NULL;
}
GtkCssValue *
{
GtkCssValue *value;
+ /* This confuses '*' and '/' so we disallow backwards compat. */
+ flags &= ~GTK_CSS_NUMBER_AS_PIXELS;
+ /* This can only be handled at compute time, we allow '-' after all */
+ flags &= ~GTK_CSS_POSITIVE_ONLY;
+
if (!_gtk_css_parser_try (parser, "calc(", TRUE))
{
_gtk_css_parser_error (parser, "Expected 'calc('");
--- /dev/null
+a {
+ margin-left: calc(calc(1px));
+}
+
+b {
+ margin-left: calc(1px + 2s);
+}
+
+c {
+ margin-left: calc(1px - 2s);
+}
+
+d {
+ margin-left: calc(2 * 3);
+}
+
+e {
+ margin-left: calc(2px * 3px);
+}
+
+f {
+ margin-left: calc(2 / 3px);
+}
+
+g {
+ margin-left: calc(2 / 3);
+}
+
+h {
+ margin-left: calc(2px / 3px);
+}
+
+i {
+ margin-left: calc(error);
+}
+
+j {
+ margin-left: calc(1px + error);
+}
+
+k {
+ margin-left: calc(1px - error);
+}
+
+l {
+ margin-left: calc(1 * error);
+}
+
+m {
+ margin-left: calc(1 / error);
+}
+
+n {
+ margin-left: calc(1px * error);
+}
+
+o {
+ margin-left: calc(1px / error);
+}
--- /dev/null
+calc-errors.css:2: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:6: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:10: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:14: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:18: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:22: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:26: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:30: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:34: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:38: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:42: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:46: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:50: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:54: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
+calc-errors.css:58: error: GTK_CSS_PROVIDER_ERROR_SYNTAX